<!--
/**
 * author: vformAdmin
 * email: vdpadmin@163.com
 * website: https://www.vform666.com
 * date: 2021.08.18
 * remark: 如果要分发VForm源码，需在本文件顶部保留此文件头信息！！
 */
-->

<template>
  <el-form :label-position="labelPosition" :size="size" :class="[customClass, readModeFlag ? 'readonly-mode-form' : '']" class="render-form"
           :label-width="labelWidth" :validate-on-rule-change="false"
           :model="formDataModel" ref="renderForm"
           :inline-message="true"
           :scroll-to-error="true"
           :style="{ 'width': formWidth, 'margin': '0 auto', 'box-sizing': 'border-box' }"
           @submit.prevent>
    <template v-for="(widget, index) in widgetList">
      <template v-if="'container' === widget.category">
        <component :is="getContainerWidgetName(widget)" :widget="widget" :key="widget.id" :parent-list="widgetList"
                        :index-of-parent-list="index" :parent-widget="null">
          <!-- 递归传递插槽！！！ -->
          <template v-for="slot in Object.keys($slots)" v-slot:[slot]="scope">
            <slot :name="slot" v-bind="scope"/>
          </template>
        </component>
      </template>
      <template v-else>
        <component :is="getWidgetName(widget)" :field="widget" :designer="null" :key="widget.id" :parent-list="widgetList"
                      :index-of-parent-list="index" :parent-widget="null">
          <!-- 递归传递插槽！！！ -->
          <template v-for="slot in Object.keys($slots)" v-slot:[slot]="scope">
            <slot :name="slot" v-bind="scope" />
          </template>
        </component>
      </template>
    </template>
  </el-form>
</template>

<script>
  import { createVNode, render } from 'vue'
  import emitter from '@/utils/emitter'
  import './container-item/index'
  import FieldComponents from '@/components/form-designer/form-widget/field-widget/index'
  import {
    generateId,
    deepClone,
    insertCustomCssToHead,
    insertGlobalFunctionsToHtml,
    getAllContainerWidgets,
    getAllFieldWidgets,
    buildDefaultFormJson,
    getDSByName,
    runDataSourceRequest,
    getFieldWidgetByName,
    overwriteObj,
    getContainerWidgetByName,
    traverseFieldWidgetsOfContainer,
    cloneFormConfigWithoutEventHandler,
    getDefaultFormConfig,
    getFieldWidgetById,
    hasPropertyOfObject,
    getObjectValue,
    setObjectValue,
    deleteCustomStyleAndScriptNode,
    objectKeysToArray,
    getVantWidget,
    getSubFormNameByFieldId,
    widgetIsSubFormType
  } from "@/utils/util"
  import i18n, { changeLocale } from "@/utils/i18n"
  import DynamicDialog from './dynamic-dialog'
  import DynamicDrawer from './dynamic-drawer'
  import setIntroduction from '@/utils/setIconfont';
  import dayjs from "dayjs";

  export default {
    name: "VFormRender",
    componentName: 'VFormRender',
    mixins: [emitter, i18n],
    components: {
      //ElForm,

      ...FieldComponents,
    },
    props: {
      formJson: { //prop传入的表单JSON配置
        type: Object,
        default: () => buildDefaultFormJson()
      },
      formData: { //prop传入的表单数据
        type: Object,
        default: () => ({})
      },
      optionData: { //prop传入的选项数据
        type: Object,
        default: () => ({})
      },
      previewState: { //是否表单预览状态
        type: Boolean,
        default: false
      },
      disabledMode: { //表单禁止编辑模式
        type: Boolean,
        default: false,
      },
      renderConfig: { //渲染配置对象
        type: Object,
        default: () => {
          return {
            languageName: 'zh-CN',  //界面语言，默认显示中文
          }
        }
      },
      globalDsv: { // 全局数据源变量
        type: Object,
        default: () => ({})
      },
      parentForm: {
        type: Object,
        default: null
      },
      dynamicCreation: { //是否弹窗、抽屉动态创建的VFormRender
        type: Boolean,
        default: false
      },
      mixMode: { // 是否使用混合渲染模式（部分组件移动端用Vant组件渲染）
        type: Boolean,
        default: false
      },
      layoutType: {  // 指定渲染布局类型，优先级高于formConfig对象的layoutType属性
        type: String,
        default: null
      },
      responsiveLayoutDisabled: {  //禁用响应式布局，默认不禁用
        type: Boolean,
        default: false
      }
    },
    provide() {
      return {
        refList: this.widgetRefList,
        sfRefList: this.subFormRefList,  //收集SubForm引用
        getFormConfig: () => this.formJsonObj.formConfig,  /* 解决provide传递formConfig属性的响应式更新问题！！ */
        getGlobalDsv: () => this.globalDsv, // 全局数据源变量
        globalOptionData: this.optionData,
        getOptionData: () => this.optionData,  /* 该方法用于在异步更新option-data之后重新获取到最新值 */
        globalModel: {
          formModel: this.formDataModel,
        },
        previewState: this.previewState,
        getReadMode: () => this.readModeFlag,
        getSubFormFieldFlag: () => false,
        getSubFormName: () => '',
        getObjectFieldFlag: () => false,  //是否对象容器字段
        getObjectName: () => '',  //返回对象容器的名称
        getDSResultCache: () => this.dsResultCache,
        isMixMode: () => this.mixMode,
        getLayoutType: () => this.layoutType,
        responsiveLayoutIsDisabled: () => this.responsiveLayoutDisabled,
        setCETriggerFlag: () => {
          this.changeEventTriggerFlag = true
        },
        clearCETriggerFlag: () => {
          this.changeEventTriggerFlag = false
        },
        getCEOCDisabledFlag: () => this.changeEventOnCreatedDisabledFlag,
      }
    },
    data() {
      return {
        formJsonObj: this.formJson,

        formDataModel: {
          //
        },

        widgetRefList: {},
        subFormRefList: {},
        formId: null,  //表单唯一Id，用于区分页面上的多个v-form-render组件！！

        externalComponents:  {},  //外部组件实例集合
        readModeFlag: false,  //是否只读查看模式
        dialogOrDrawerRef: null, //保存子级VFormRender的包裹弹窗组件或抽屉组件的ref
        childFormRef: null, //保存子级VFormRender组件的ref
        changeEventTriggerFlag: false, //记录onChange事件是否由用户操作触发
        changeEventOnCreatedDisabledFlag: false, //记录组件创建时是否禁止触发onChange事件，默认不禁止触发

        dsResultCache: {},  //数据源请求结果缓存
      }
    },
    computed: {
      formConfig() {
        return this.formJsonObj.formConfig
      },

      widgetList() { // 目前渲染暂不需要widgetViewList 根据返回值赋值widgetList即可
        return this.formJsonObj.widgetList
      },

      labelPosition() {
        if (!!this.layoutType && (this.layoutType === 'H5') && this.formConfig.h5LabelTop) {
          return 'top'
        }
        
        if (!!this.formConfig && (this.formConfig.layoutType === 'H5') && this.formConfig.h5LabelTop) {
          return 'top'
        }

        if (!!this.formConfig && !!this.formConfig.labelPosition) {
          return this.formConfig.labelPosition
        }

        return 'left'
      },

      labelWidth() {
        if (!!this.formConfig && !!this.formConfig.labelWidth) {
          return this.formConfig.labelWidth + 'px'
        }

        return '80px'
      },

      size() {
        if (!!this.formConfig && !!this.formConfig.size) {
          return this.formConfig.size
        }

        return 'default'
      },

      customClass() {
        return !!this.formConfig && !!this.formConfig.customClass ? this.formConfig.customClass : ''
      },

      formWidth() {
        if (this.formConfig && this.formConfig.formWidth) {
          return this.formConfig.formWidth + (this.formConfig.formWidthUnit || '%');
        } else {
          return '100%';
        }
      }

    },
    watch: {
      //
    },
    created() {
      this.buildFormModel(!this.formJsonObj ? null : this.formJsonObj.widgetList)
      this.initFormObject()
    },
    mounted() {
      // 设置批量第三方 icon 图标
      setIntroduction.cssCdn();
      // 设置批量第三方 js
      setIntroduction.jsCdn();

      this.initLocale()
      this.initDataSetRequest()
      this.handleOnMounted()
    },
    beforeUnmount() {
      deleteCustomStyleAndScriptNode(this.previewState, this.formId)
    },
    methods: {
      initFormObject(insertHtmlCodeFlag = true) {
        this.formId = 'vfRender' + generateId()
        if (!!insertHtmlCodeFlag && !this.dynamicCreation) { // 弹窗、抽屉动态创建的VFormRender不重新插入全局CSS和全局函数节点！！
          this.insertCustomStyleAndScriptNode()
        }
        this.addFieldChangeEventHandler()
        this.addFieldValidateEventHandler()
        this.registerFormToRefList()
        this.handleOnCreated()

        if (!!this.disabledMode) { //禁止表单编辑
          this.$nextTick(() => {
            this.disableForm()
          })
        }
      },

      getContainerWidgetName(widget) {
        if (widget.type === 'grid') {  //grid-item跟VueGridLayout全局注册组件重名，故特殊处理！！
          return 'vf-grid-item'
        }

        return widget.type + '-item'
      },

      getWidgetName(widget) {
        // return widget.type + '-widget'
        return getVantWidget(this.mixMode, widget.type) + '-widget'
      },

      initLocale() {
        let curLocale = localStorage.getItem('v_form_locale') || 'zh-CN'
        this.changeLanguage(curLocale)
      },

      insertCustomStyleAndScriptNode() {
        if (!!this.formConfig && !!this.formConfig.cssCode) {
          insertCustomCssToHead(this.formConfig.cssCode,
              !!this.previewState ? '' : this.formId)
        }

        if (!!this.formConfig && !!this.formConfig.functions) {
          insertGlobalFunctionsToHtml(this.formConfig.functions,
              !!this.previewState ? '' : this.formId)
        }
      },

      buildFormModel(widgetList) {
        if (!!widgetList && (widgetList.length > 0)) {
          widgetList.forEach((wItem) => {
            this.buildDataFromWidget(wItem)
          })
        }
      },

      getFieldKeyName(field) {
        let fieldKeyName = field.options.name
        return field.options.keyNameEnabled ? (field.options.keyName || fieldKeyName) : fieldKeyName
      },

      buildDataFromWidget(wItem) {
        if (wItem.category === 'container') {
          if (wItem.type === 'vf-dialog' || wItem.type === 'vf-drawer') {
            // 什么也不做，不处理弹窗、抽屉内部组件！！
          } else if (wItem.type === 'grid' || wItem.type === 'left-right') {
            if (!!wItem.cols && (wItem.cols.length > 0)) {
              wItem.cols.forEach((childItem) => {
                this.buildDataFromWidget(childItem)
              })
            }
          } else if (wItem.type === 'table') {
            if (!!wItem.rows && (wItem.rows.length > 0)) {
              wItem.rows.forEach((rowItem) => {
                if (!!rowItem.cols && (rowItem.cols.length > 0)) {
                  rowItem.cols.forEach((colItem) => {
                    this.buildDataFromWidget(colItem)
                  })
                }
              })
            }
          } else if (wItem.type === 'tab') {
            if (!!wItem.tabs && (wItem.tabs.length > 0)) {
              wItem.tabs.forEach((tabItem) => {
                if (!!tabItem.widgetList && (tabItem.widgetList.length > 0)) {
                  tabItem.widgetList.forEach((childItem) => {
                    this.buildDataFromWidget(childItem)
                  })
                }
              })
            }
          } else if (wItem.type === 'sub-form' || wItem.type === 'table-sub-form') {
            let subFormName = wItem.options.name
            if (!this.formData.hasOwnProperty(subFormName)) {
              let subFormDataRow = {}
              if (wItem.options.showBlankRow) {
                wItem.widgetList.forEach(subFormItem => {
                  if (!!subFormItem.formItemFlag) {
                    let sfiKeyName = this.getFieldKeyName(subFormItem)
                    subFormDataRow[sfiKeyName] = subFormItem.options.defaultValue
                  }
                })

                this.formDataModel[subFormName] = [subFormDataRow]
              } else {
                this.formDataModel[subFormName] = []
              }
            } else {
              let initialValue = this.formData[subFormName]
              this.formDataModel[subFormName] = deepClone(initialValue)
            }
          } else if (wItem.type === 'grid-sub-form')  {
            let gridSubFormName = wItem.options.name
            if (!this.formData.hasOwnProperty(gridSubFormName)) {
              let gsfFWList = []
              let fieldListFn = (fw) => {
                gsfFWList.push(fw)
              }
              traverseFieldWidgetsOfContainer(wItem, fieldListFn)

              let gridSubFormDataRow = {}
              if (wItem.options.showBlankRow) {
                gsfFWList.forEach(gridSubFormItem => {
                  let sfiKeyName = this.getFieldKeyName(gridSubFormItem)
                  gridSubFormDataRow[sfiKeyName] = gridSubFormItem.options.defaultValue
                })
                this.formDataModel[gridSubFormName] = [gridSubFormDataRow]
              } else {
                this.formDataModel[gridSubFormName] = []
              }
            } else {
              let initialValue = this.formData[gridSubFormName]
              this.formDataModel[gridSubFormName] = deepClone(initialValue)
            }
          } else if ((wItem.type === 'grid-col') || (wItem.type === 'table-cell')) {
            if (!!wItem.widgetList && (wItem.widgetList.length > 0)) {
              wItem.widgetList.forEach((childItem) => {
                this.buildDataFromWidget(childItem)
              })
            }
          } else if (wItem.type === 'object-group') { // 处理对象容器内部字段！！
            let objectFields = []
            traverseFieldWidgetsOfContainer(wItem, (fld) => {
              if (!!fld.formItemFlag) {
                objectFields.push(fld.options.name)
              }
            })

            let objectName = wItem.options.objectName
            objectFields.forEach(fieldName => {
              let fieldSchema = getFieldWidgetByName(wItem.widgetList, fieldName, false)
              let objPath = objectName + '.' + this.getFieldKeyName(fieldSchema)
              if (!hasPropertyOfObject(this.formData, objPath)) {
                setObjectValue(this.formDataModel, objPath, fieldSchema.options.defaultValue)
              } else {
                let initialValue = getObjectValue(this.formData, objPath)
                setObjectValue(this.formDataModel, objPath, initialValue)
              }
            })
          } else {  //自定义容器组件
            if (!!wItem.widgetList && (wItem.widgetList.length > 0)) {
              wItem.widgetList.forEach((childItem) => {
                this.buildDataFromWidget(childItem)
              })
            }
          }
        } else if (!!wItem.formItemFlag) {
          let fKeyName = this.getFieldKeyName(wItem)
          if (!this.formData.hasOwnProperty(fKeyName)) {
            this.formDataModel[fKeyName] = wItem.options.defaultValue
          } else {
            let initialValue = this.formData[fKeyName]
            this.formDataModel[fKeyName] = deepClone(initialValue)
          }
        }
      },

      addFieldChangeEventHandler() {
        this.off$('fieldChange')  //移除原有事件监听
        this.on$('fieldChange', ([fieldName, newValue, oldValue, subFormName, subFormRowIndex]) => {  /* 注意：这里事件入参是数组，必须先解构！！ */
          this.handleFieldDataChange(fieldName, newValue, oldValue, subFormName, subFormRowIndex)
          this.$emit('formChange', fieldName, newValue, oldValue, this.formDataModel, subFormName, subFormRowIndex)
        })
      },

      addFieldValidateEventHandler() {
        this.off$('fieldValidation')  //移除原有事件监听
        this.on$('fieldValidation', (fieldName) => {
          if (!!this.$refs.renderForm) {
            this.$refs.renderForm.validateField(fieldName)
          }
        })
      },

      registerFormToRefList() {
        this.widgetRefList['v_form_ref'] = this
      },

      handleFieldDataChange(fieldName, newValue, oldValue, subFormName, subFormRowIndex) {
        if (!!this.formConfig && !!this.formConfig.onFormDataChange) {
          let customFunc = new Function('fieldName', 'newValue', 'oldValue', 'formModel', 'subFormName', 'subFormRowIndex',
              this.formConfig.onFormDataChange)
          customFunc.call(this, fieldName, newValue, oldValue, this.formDataModel, subFormName, subFormRowIndex)
        }
      },

      handleOnCreated() {
        if (!!this.formConfig && !!this.formConfig.onFormCreated) {
          let customFunc = new Function(this.formConfig.onFormCreated)
          customFunc.call(this)
        }
      },

      handleOnMounted() {
        this.$emit('onFormMounted')
        if (!!this.formConfig && !!this.formConfig.onFormMounted) {
          let customFunc = new Function(this.formConfig.onFormMounted)
          customFunc.call(this)
        }
      },

      findWidgetAndSetDisabled(widgetName, disabledFlag) {
        let foundW = this.getWidgetRef(widgetName)
        if (!!foundW && !!foundW.setDisabled) {
          foundW.setDisabled(disabledFlag)
        } else { //没找到，可能是子表单中的组件
          this.findWidgetOfSubFormAndSetDisabled(widgetName, disabledFlag)
        }
      },

      findWidgetOfSubFormAndSetDisabled(widgetName, disabledFlag) {
        const widgetSchema = getFieldWidgetByName(this.formJsonObj.widgetList, widgetName, true)
        if (!!widgetSchema && !!widgetSchema.options && widgetSchema.options.hasOwnProperty('disabled')) {
          widgetSchema.options.disabled = disabledFlag
        }

        this.findWidgetNameInSubForm(widgetName).forEach(wn => {
          let sw = this.getWidgetRef(wn)
          if (!!sw && !!sw.setDisabled) {
            sw.setDisabled(disabledFlag)
          }
        })
      },

      findWidgetAndSetHidden(widgetName, hiddenFlag) {
        let foundW = this.getWidgetRef(widgetName)
        if (!!foundW && !!foundW.setHidden) {
          foundW.setHidden(hiddenFlag)
        } else { //没找到，可能是子表单中的组件
          this.findWidgetOfSubFormAndSetHidden(widgetName, hiddenFlag)
        }
      },

      findWidgetOfSubFormAndSetHidden(widgetName, hiddenFlag) {
        const widgetSchema = getFieldWidgetByName(this.formJsonObj.widgetList, widgetName, true)
        if (!!widgetSchema && !!widgetSchema.options && widgetSchema.options.hasOwnProperty('hidden')) {
          widgetSchema.options.hidden = hiddenFlag
        }

        this.findWidgetNameInSubForm(widgetName).forEach(wn => {
          let sw = this.getWidgetRef(wn)
          if (!!sw && !!sw.setHidden) {
            sw.setHidden(hiddenFlag)
          }
        })
      },

      findWidgetNameInSubForm(widgetName) {
        let result = []
        let subFormName = null
        let newWidgetName = widgetName

        if (widgetName.indexOf('@sf=') > -1) {
          subFormName = widgetName.substring(widgetName.indexOf('@sf=') + 4)
          newWidgetName = widgetName.substring(0, widgetName.indexOf('@sf='))
        } else {
          Object.keys(this.subFormRefList).forEach(sfName => {
            const fwHandler = (fw) => {
              if (fw.options.name === widgetName) {
                subFormName = sfName
              }
            }

            const sfRef = this.subFormRefList[sfName]
            traverseFieldWidgetsOfContainer(sfRef.widget, fwHandler, true)
          })
        }

        if (!!subFormName) {
          let subFormRef = this.getWidgetRef(subFormName)
          if (!!subFormRef) {
            let rowIds = subFormRef.getRowIdData()
            if (!!rowIds && (rowIds.length > 0)) {
              rowIds.forEach(rid => {
                result.push(newWidgetName + '@row' + rid)
              })
            }
          }
        }

        return result
      },

      findFieldWidgetById(fieldId, staticWidgetsIncluded) {
        return getFieldWidgetById(this.formJsonObj.widgetList, fieldId, staticWidgetsIncluded)
      },

      initDataSetRequest() {
        let dsNameSet = new Set()
        this.getFieldWidgets().forEach(fw => {
          if (!!fw.field.options.dsEnabled && !!fw.field.options.dsName && !!fw.field.options.dataSetName) {
            dsNameSet.add(fw.field.options.dsName)
          }
        })

        if (dsNameSet.size > 0) {
          dsNameSet.forEach(async (dsName) => {
            let curDS = getDSByName(this.formConfig, dsName)
            if (!!curDS) {
              let localDsv = new Object({})
              overwriteObj(localDsv, this.globalDsv || {})
              let dsResult = null
              try {
                dsResult = await runDataSourceRequest(curDS, localDsv, this, false, this.$message)
                this.dsResultCache[dsName] = dsResult
                this.broadcast('FieldWidget', 'loadOptionItemsFromDataSet', dsName)  //注意：跟Vue2不同，事件参数不需要包含在数组中传递！！
              } catch (err) {
                this.$message.error(err.message)
              }
            }
          })
        }
      },

      //--------------------- 以下为组件支持外部调用的API方法 begin ------------------//
      /* 提示：用户可自行扩充这些方法！！！ */

      changeLanguage(langName) {
        changeLocale(langName)
      },

      getLanguageName() {
        return localStorage.getItem('v_form_locale') || 'zh-CN'
      },

      getNativeForm() { //获取原生form引用
        return this.$refs['renderForm']
      },

      getFormRef() {
        return this
      },

      getWidgetRef(widgetName, showError = false) {
        let foundRef = this.widgetRefList[widgetName]
        // 查不到时，尝试通过keyName查找
        if (!foundRef) {
          foundRef = this.getWidgetRefByKeyName(widgetName)
        }
        if (!foundRef && !!showError) {
          this.$message.error(this.i18nt('render.hint.refNotFound') + widgetName)
        }
        return foundRef
      },

      /**
       * 根据keyName获取组件引用
       * @param keyName 组件的keyName属性
       */
      getWidgetRefByKeyName(keyName) {
        let foundRef = null;
        Object.keys(this.widgetRefList).forEach(k => {
          const currentWidgetRef = this.widgetRefList[k]
          const currentOptions = currentWidgetRef?.field?.options
          if ((currentOptions?.name === keyName || currentOptions?.keyName === keyName) && currentOptions?.name == k) {
            foundRef = currentWidgetRef
          }
        })
        return foundRef
      },

      clearFormDataModel() {
        for (let pkey in this.formDataModel) {
          delete this.formDataModel[pkey]
        }
      },

      getFormJson() {
        return this.formJsonObj
      },

      /**
       * 动态加载表单JSON
       * @param newFormJson
       */
      setFormJson(newFormJson) {
        if (!!newFormJson) {
          if ((typeof newFormJson === 'string') || (newFormJson.constructor === Object)) {
            let newFormJsonObj = null
            if (typeof newFormJson === 'string') {
              newFormJsonObj = JSON.parse(newFormJson)
            } else {
              newFormJsonObj = newFormJson
            }

            if (!newFormJsonObj.formConfig || !newFormJsonObj.widgetList) {
              this.$message.error('Invalid format of form json.')
              return
            }

            /* formDataModel必须在widgetList赋值完成初始化，因为widgetList赋值意味着子组件开始创建！！！ */
            //this.formDataModel = {}  //清空表单数据对象（有bug，会导致表单校验失败！！）
            this.clearFormDataModel()  //上行代码有问题，会导致表单校验失败，故保留原对象引用只清空对象属性！！
            this.buildFormModel(newFormJsonObj.widgetList)

            this.formJsonObj['formConfig'] = newFormJsonObj.formConfig
            this.formJsonObj['widgetList'] = newFormJsonObj.widgetList

            this.insertCustomStyleAndScriptNode()  /* 必须先插入表单全局函数，否则VForm内部引用全局函数会报错！！！ */
            this.$nextTick(() => {
              this.initFormObject(false)
              this.initDataSetRequest()
              this.handleOnMounted()
            })
          } else {
            this.$message.error('Set form json failed.')
          }
        }
      },

      /**
       * 重新加载选项数据
       * @param widgetNames 指定重新加载的组件名称或组件名数组，不传则重新加载所有选项字段
       */
      reloadOptionData(widgetNames) {
        let eventParams = []
        if (!!widgetNames && (typeof widgetNames === 'string')) {
          eventParams = [widgetNames]
        } else if (!!widgetNames && Array.isArray(widgetNames)) {
          eventParams = [...widgetNames]
        }
        this.broadcast('FieldWidget', 'reloadOptionItems', eventParams)
      },

      async getFormData(needValidation = true) {
        return this.doGetFormData(this.formDataModel, needValidation)
      },

      async doGetFormData(fdModel, needValidation = true) {
        // 注意这里 不走表单校验也需要进行数据格式化处理
        if (!needValidation) {
          return Promise.resolve(await this.resetFormData(fdModel));
        }

        let callback = function nullFunc() {}
        const _this = this
        let promise = new window.Promise(function (resolve, reject) {
          callback = function(formData, error) {
            // !error ? resolve(formData) : reject(error);
            let newFormData = formData
            // if (_this.globalDsv.vformDataV && _this.globalDsv.vformDataV === 'V1') {
              newFormData = _this.resetFormData(formData)
            // }
            !error ? resolve(newFormData) : reject(error);
          };
        });

        this.$refs['renderForm'].validate(async (valid, invalidFields) => {
          //console.error('invalidFields: ', invalidFields)
          if (valid) {
            //执行表单自定义校验
            let customValid = await this.doCustomValidation()
            if (customValid) {
              callback(fdModel)
            } else {
              // callback(fdModel, this.i18nt('render.hint.validationFailed') + ': ' + JSON.stringify(objectKeysToArray(invalidFields)))
              callback(fdModel, invalidFields)
            }
          } else {
            // callback(fdModel, this.i18nt('render.hint.validationFailed') + ': ' + JSON.stringify(objectKeysToArray(invalidFields)))
            callback(fdModel, invalidFields)
          }
        })

        return promise
      },

      /**
       * 表单数据取值扩展方法，支持tree、data-table组件
       * @param needValidation
       */
       getFormDataEx(needValidation = true) {
        const formDataModelEx = deepClone(this.formDataModel)
        //要排除弹窗或抽屉里的组件
        const cwWidgets = this.getContainerWidgets(true)
        cwWidgets.map(cwItem => {
          if (cwItem.type === 'tree') {
            const treeRef = this.getWidgetRef(cwItem.name)
            if (treeRef) {
              formDataModelEx[cwItem.name] = treeRef.getCheckedNodes(false, false)
            }
          } else if (cwItem.type === 'data-table') {
            const dtRef = this.getWidgetRef(cwItem.name)
            if (dtRef) {
              formDataModelEx[cwItem.name] = dtRef.getSelectedRowKeys()
            }
          }
        })

        return this.doGetFormData(formDataModelEx, needValidation)
      },

      /**
       * 重置表单数据-统一字段格式
       * @param formDataModel formData对象，用于获取每个组件数值
       */
      async resetFormData(formDataModel) {
        try {
          const allWidgets = await this.getFieldWidgets().concat(await this.getContainerWidgets());
          // console.log("allWidgets", allWidgets );
          const newValue = {};
          for (const item of allWidgets) {
            if (['wps-word', 'wps-pdf'].includes(item.type)) {
              newValue[item.name] = formDataModel[item.name]
              continue;
            }
            for (const key of Object.keys(formDataModel)) {
              if (key === item.name || key === item.field?.options?.keyName) {
                let defaultValue = formDataModel[key];
                if (item.type === 'select-unit' && this.isJSON(defaultValue)) {
                  defaultValue = JSON.parse(defaultValue);
                }
                if (!newValue[key]) {
                  newValue[key] = [];
                }
                if (item.type !== "serial-number" && (defaultValue === null || defaultValue === "" || defaultValue === undefined)) {
                  newValue[key] = "";
                } else if (Array.isArray(defaultValue) && !defaultValue.length) {
                  newValue[key] = [];
                } else if (Array.isArray(defaultValue) && defaultValue.length && !item.type.includes('-range')) {
                  let index = 0;
                  for (let value of defaultValue) {
                    const newData = await this.createNewData(value, item.type, item.type === 'sub-form' || item.type === 'grid-sub-form' ? item.container.options : item.field.options);
                    if (item.type !== 'process-comments') {
                      if (index === 0) {
                        newData.defaultValue = item.type === 'select-unit' ? JSON.stringify(defaultValue) : defaultValue;
                        if (item.type === 'checkbox-with-input') {
                          // 创建一个对象来存储两种数据
                          newData.defaultValue = {
                            selectedValues: defaultValue, // 保存原始的选中值数组
                            optionsConfig: item.field?.options.optionItems // 保存选项配置
                          };
                        }
                      } else {
                        delete newData.defaultValue;
                      }
                    } else {
                      // 过滤分发意见格式为字符串数据
                      if (typeof newData.defaultValue == "string") {
                        continue;
                      }
                    }
                    if (item.type ===  'sub-form' || item.type === 'grid-sub-form') {
                      delete newData.defaultValue;
                    }
                    newValue[key].push(newData);
                    index++;
                  }
                } else {
                  const newData = await this.createNewData(defaultValue, item.type, item.field.options);
                  newValue[key].push(newData);
                }
              }
            }
          }
          return newValue;
        } catch (err) {
          console.error(err);
          throw err;
        }
      },

      /**
       * 创建统一字段对象
       * @param value 组件对应数组
       * @param type 组件类型
       * @param options 组件配置
       */
      async createNewData(value, type, options) {
        let data = {
          zhlx_gjz_id: value,
          zhlx_gjz_label: value,
          zhlx_gjz_sortOrder: 0,
          zhlx_gjz_component_type: type,
          zhlx_gjz_component_label: options.label,
          defaultValue: value,
        };
        if (!(type === 'select' || type === 'radio' || type === 'checkbox' || type === 'checkbox-with-input' || type === "date" || type === "serial-number" || type === "number")) {
          if (!value || Array.isArray(value) && !value.length || typeof value !== "object") {
            return data;
          }
        }
        if (type === 'number') {
          if (options.numDisplayFormat == "percent") {
            data.zhlx_gjz_label = Number(value).toLocaleString('zh', {style:'percent', minimumFractionDigits: options.percentPrecision})
          } else if (options.numDisplayFormat == "subcontractor") {
            data.zhlx_gjz_label = Number(value).toLocaleString('zh', {minimumFractionDigits: options.precision})
          }
        } else if (type === 'serial-number') { // 流水号组件
          if (options.bindSerialNum) {
            data.bindSerialNum = options.bindSerialNum
          }
        } else if (type === 'file-list') { // 附件列表
          data.zhlx_gjz_id = value.id;
          data.zhlx_gjz_label = value.originalFilename;
        } else if (type === 'select-unit') { // 抄送组件
          data.zhlx_gjz_id = value.id;
          data.zhlx_gjz_label = value.name;
        } else if (type.includes('select-') && type !== 'select-process') { // 选人组件
          data.zhlx_gjz_id = value.mainId;
          data.zhlx_gjz_label = value.mainName;
          data.objectType = value.objectType;
          data.tenantId = value.tenantId;
        } else if (type === 'select-process') { // 流程选择组件
          data.zhlx_gjz_id = value.exampleId;
          data.zhlx_gjz_label = value.exampleTitle;
        } else if (type === 'process-comments') { // 流程意见
          data.zhlx_gjz_id = value.nodeCode;
          data.zhlx_gjz_label = value.handleOpinion;
        } else if (type === 'select' || type === 'radio' || type === 'checkbox' || type === 'checkbox-with-input') { // 下拉/单选框/多选框
          const selectData = options.optionItems.find(select => select[options.valueKey || "value"] == value);
          if (!!selectData) {
            data.zhlx_gjz_id = selectData[options.valueKey || "value"];
            data.zhlx_gjz_label = selectData[options.labelKey || "label"];
          }
        } else if (type === 'date' || type === 'date-range') { // 日期/日期范围
          const chFormatDate = {
            "YYYY年MM月DD日" : "YYYY[年]MM[月]DD[日]",
            "YYYY年M月D日" : "YYYY[年]M[月]D[日]",
            "YYYY年MM月DD日 HH时mm分ss秒" : "YYYY[年]MM[月]DD[日] HH[时]mm[分]ss[秒]",
            "YYYY年M月D日 HH时mm分" : "YYYY[年]M[月]D[日] HH[时]mm[分]",
          }
          let dateValue = value
          // 处理日期类型字段的默认值 时间戳字符串转换
          if (type === 'date') {
            dateValue += ''
            const formatDate = this.getNumericValue(value)
            data.zhlx_gjz_label = value ? dayjs(typeof formatDate === 'string' ? formatDate.replace(/年|月/g, '-').replace(/时|分/g, ':').replace(/日|秒/g, '') : formatDate).format(chFormatDate[options.format] || options.format) : '';
            data.zhlx_gjz_id = data.defaultValue = dateValue;
          } else if (type === 'date-range') {
            dateValue = value?.length ? value.map((item) => item += '') : []
            data.zhlx_gjz_label = value.map(item => dayjs(this.getNumericValue(item)).format(chFormatDate[options.format] || options.format)).join('~');
            data.zhlx_gjz_id = dateValue?.length ? dateValue.join('~') : dateValue;
            data.defaultValue = dateValue
          }
        } else if (type === 'time-range') { // 时间范围
          data.zhlx_gjz_id = Array.isArray(value) ? value.join('~') : value;
          data.zhlx_gjz_label = data.zhlx_gjz_id;
        } else if (type === 'sub-form' || type === 'grid-sub-form') { // 子表单
          data.zhlx_gjz_id = "";
          data.zhlx_gjz_label = "";
          if (value && Object.keys(value).length) {
            data.zhlx_gjz_subform_value = await this.resetFormData(value)
          }
        }
        return data;
      },
      /**
       * 判断是否是json字符串
       */
      isJSON(str) {
        try {
          JSON.parse(str);
        } catch (e) {
          return false;
        }
        return true;
      },
      /**
       * 解析数字字符串-转化为数字
       * @param value 传入的数字字符串
       */
      getNumericValue(value) {
        // 正则表达式匹配字符串形式的数字
        const isNumericString = /^-?\d+(\.\d+)?$/;
        // 检查是否是字符串形式的数字 - 表示是时间戳
        if (typeof value === 'string' && isNumericString.test(value)) {
          // 转换为数字
          return Number(value);
        }

        // 如果有值且是字符类型
        if (value && typeof value === 'string') {
          let cloneValue = deepClone(value)
          cloneValue = cloneValue.replace(/(年)|(月)/g, '-')
          cloneValue = cloneValue.replace(/(时)|(分)/g, ':')
          cloneValue = cloneValue.replace(/(日)|(秒)/g, '')
          return new Date(cloneValue).getTime();
        }
        
        // 如果不是字符串形式的数字，直接返回
        return value;
      },

      /**
       * 表单数据赋值扩展方法，不支持tree、data-table组件
       * @param formData
       * @param disableChangeEvent 是否禁止触发change事件，默认不禁止（无法控制是否触发子表单内部组件的change事件!!!）
       */
       setFormData(formData, disableChangeEvent = false) { //设置表单数据
        let formDataObj = formData
        if (typeof formData === 'string') {
          formDataObj = JSON.parse(formData)
        }
        Object.keys(this.formDataModel).forEach(propName => {
          if (!!formDataObj && formDataObj.hasOwnProperty(propName)) {
            this.formDataModel[propName] = deepClone( formDataObj[propName] )
          }
        })

        this.setCEOCDisabledFlag(disableChangeEvent)
        // 通知SubForm组件：表单数据更新事件！！
        this.broadcast('ContainerItem', 'setFormData', [this.formDataModel, disableChangeEvent])
        // 通知FieldWidget组件：表单数据更新事件！！
        this.broadcast('FieldWidget', 'setFormData', [this.formDataModel, disableChangeEvent])
      },

      /**
       * 表单数据赋值扩展方法，支持tree、data-table组件
       * @param formData
       * @param disableChangeEvent
       */
       setFormDataEx(formData, disableChangeEvent = false) {
        let formDataObj = formData
        if (typeof formData === 'string') {
          formDataObj = JSON.parse(formData)
        }
        this.setFormData(formDataObj, disableChangeEvent)

        // 通知tree、data-table组件：表单数据更新事件！！
        this.broadcast('ContainerItem', 'setFormDataEx', formDataObj)
      },

      getFieldValue(fieldName) { //单个字段获取值
        let fieldRef = this.getWidgetRef(fieldName)
        if (!!fieldRef && !!fieldRef.getValue) {
          return fieldRef.getValue()
        }

        if (!fieldRef) { //如果是子表单字段
          let result = []
          this.findWidgetNameInSubForm(fieldName).forEach(wn => {
            let sw = this.getWidgetRef(wn)
            if (!!sw && !!sw.getValue) {
              result.push( sw.getValue() )
            }
          })

          return result
        }
      },

      setFieldValue(fieldName, fieldValue, disableChangeEvent = false) { //单个更新字段值
        let fieldRef = this.getWidgetRef(fieldName)
        if (!!fieldRef && !!fieldRef.setValue) {
          fieldRef.setValue(fieldValue, disableChangeEvent)
        }

        if (!fieldRef) { //如果是子表单字段
          this.findWidgetNameInSubForm(fieldName).forEach(wn => {
            let sw = this.getWidgetRef(wn)
            if (!!sw && !!sw.setValue) {
              sw.setValue(fieldValue, disableChangeEvent)
            }
          })
        }
        /* 主动触发表单的单个字段校验，用于清除字段可能存在的校验错误提示 */
        if (!!this.$refs.renderForm) {
          this.$refs.renderForm.validateField(fieldName)
        }
      },

      getSubFormValues(subFormName, needValidation = true) {
        let foundSFRef = this.subFormRefList[subFormName]
        return foundSFRef.getSubFormValues(needValidation)
      },

      setSubFormValues(subFormName, subFormValues) {
        let foundSFRef = this.subFormRefList[subFormName]
        return foundSFRef.setSubFormValues(subFormValues)
      },

      disableForm() {
        let wNameList = Object.keys(this.widgetRefList)
        wNameList.forEach(wName => {
          let foundW = this.getWidgetRef(wName)
          
          if (!!foundW) {
            if (!!foundW.widget && (foundW.widget.type === 'sub-form' || foundW.widget.type === 'table-sub-form')) {
              foundW.disableSubForm()
            } else if (!!foundW.widget && (foundW.widget.type === 'grid-sub-form')) {
              foundW.disableGridSubForm()
            } else {
              !!foundW.setDisabled && foundW.setDisabled(true)
            }
          }
        })
      },

      enableForm() {
        let wNameList = Object.keys(this.widgetRefList)
        wNameList.forEach(wName => {
          let foundW = this.getWidgetRef(wName)
          if (!!foundW) {
            if (!!foundW.widget && (foundW.widget.type === 'sub-form' || foundW.widget.type === 'table-sub-form')) {
              foundW.enableSubForm()
            } else if (!!foundW.widget && (foundW.widget.type === 'grid-sub-form')) {
              foundW.enableGridSubForm()
            } else {
              !!foundW.setDisabled && foundW.setDisabled(false)
            }
          }
        })
      },

      resetForm(disableChangeEvent = false) {  //重置表单
        let subFormNames = Object.keys(this.subFormRefList)
        subFormNames.forEach(sfName => {
          if (!!this.subFormRefList[sfName].resetSubForm) {
            this.subFormRefList[sfName].resetSubForm()
          }
        })

        let wNameList = Object.keys(this.widgetRefList)
        wNameList.forEach(wName => {
          let foundW = this.getWidgetRef(wName)
          if (!!foundW && !foundW.subFormItemFlag && !!foundW.resetField) { // 跳过子表单字段！！
            foundW.resetField(disableChangeEvent);
            // 如果需要触发change事件，则调用setValue方法 ** 2020-07-24 16:14:40 重置不出生效加的该方法
            if (!disableChangeEvent) {
              const wType = foundW.field.type;
              if (wType === 'select' || wType === 'input' || wType === 'textarea') {
                foundW.setValue('')
              } else if (wType === 'checkbox') {
                foundW.setValue([])
              } else {
                foundW.setValue(null)
              }
            }
          }
        })

        this.$nextTick(() => {
          this.clearValidate()  /* 清除resetField方法触发的校验错误提示 */
        })
      },

      /**
       * 清除表单一个或多个字段的校验提示信息
       * @param props
       */
       clearValidate(props) {
        this.$refs.renderForm.clearValidate(props)
        
        //TODO: props不传值则清空表单所有校验信息
        //待实现，可以用broadcast方法广播消息
      },

      /**
       * 校验表单
       * @param callback 回调函数
       */
      validateForm(callback) {
        this.$refs['renderForm'].validate(async (valid, invalidFields) => {
          if (valid) {
            //执行表单自定义校验
            let customValid = await this.doCustomValidation();
            callback(customValid, invalidFields)
          } else {
            callback(valid, invalidFields)
          }
        })
      },

      /**
       * 执行表单自定义校验代码
       */
      async doCustomValidation() {
        if (!this.formConfig.onFormValidate) {
          return true
        }

        const AsyncFunction = async function () {}.constructor
        let customFn = new AsyncFunction('formModel', this.formConfig.onFormValidate)
        let result = await customFn.call(this, this.formDataModel)

        return result === undefined ? true : result
      },

      validateFields() {
        //TODO
      },

      validateField(fieldName) {
        return this.$refs.renderForm.validateField(fieldName)
      },

      disableWidgets(widgetNames) {
        if (!!widgetNames) {
          if (typeof widgetNames === 'string') {
            this.findWidgetAndSetDisabled(widgetNames, true)
          } else if (Array.isArray(widgetNames)) {
            widgetNames.forEach(wn => {
              this.findWidgetAndSetDisabled(wn, true)
            })
          }
        }
      },

      enableWidgets(widgetNames) {
        if (!!widgetNames) {
          if (typeof widgetNames === 'string') {
            this.findWidgetAndSetDisabled(widgetNames, false)
          } else if (Array.isArray(widgetNames)) {
            widgetNames.forEach(wn => {
              this.findWidgetAndSetDisabled(wn, false)
            })
          }
        }
      },

      hideWidgets(widgetNames) {
        if (!!widgetNames) {
          if (typeof widgetNames === 'string') {
            this.findWidgetAndSetHidden(widgetNames, true)
          } else if (Array.isArray(widgetNames)) {
            widgetNames.forEach(wn => {
              this.findWidgetAndSetHidden(wn, true)
            })
          }
        }
      },

      showWidgets(widgetNames) {
        if (!!widgetNames) {
          if (typeof widgetNames === 'string') {
            this.findWidgetAndSetHidden(widgetNames, false)
          } else if (Array.isArray(widgetNames)) {
            widgetNames.forEach(wn => {
              this.findWidgetAndSetHidden(wn, false)
            })
          }
        }
      },

      /**
       * 批量设置字段是否必填
       * @param widgetNames
       * @param required true/false
       */
      setWidgetsRequired(widgetNames, required) {
        if (!!widgetNames) {
          if (typeof widgetNames === 'string') {
            this.findWidgetAndSetRequired(widgetNames, required)
          } else if (Array.isArray(widgetNames)) {
            widgetNames.forEach(wn => {
              this.findWidgetAndSetRequired(wn, required)
            })
          }
        }
      },

      findWidgetAndSetRequired(widgetName, required) {
        let foundW = this.getWidgetRef(widgetName)
        if (!!foundW && !!foundW.setRequired) {
          foundW.setRequired(required)
        } else { //没找到，可能是子表单中的组件
          this.findWidgetOfSubFormAndSetRequired(widgetName, required)
        }
      },
      findWidgetOfSubFormAndSetRequired(widgetName, required) {
        const widgetSchema = getFieldWidgetByName(this.formJsonObj.widgetList, widgetName, true)
        if (!!widgetSchema && !!widgetSchema.options && widgetSchema.options.hasOwnProperty('required')) {
          widgetSchema.options.required = required
        }

        this.findWidgetNameInSubForm(widgetName).forEach(wn => {
          let sw = this.getWidgetRef(wn)
          if (!!sw && !!sw.setRequired) {
            sw.setRequired(required)
          }
        })
      },
      findWidgetOfSubFormAndSetReadOnly(widgetName, readonly) {
        const widgetSchema = getFieldWidgetByName(this.formJsonObj.widgetList, widgetName, true)
        if (!!widgetSchema && !!widgetSchema.options && widgetSchema.options.hasOwnProperty('readonly')) {
          widgetSchema.options.readonly = readonly
        }

        this.findWidgetNameInSubForm(widgetName).forEach(wn => {
          let sw = this.getWidgetRef(wn)
          if (!!sw && !!sw.setReadonly) {
            sw.setReadonly(readonly)
          }
        })
      },

      /* 注意：该方法已被弃用，当多个子表单存在同名组件时会出问题！！！ */
      getSubFormNameOfWidget(widgetName) {
        let result = []
        let subFormName = null
        Object.keys(this.subFormRefList).forEach(sfName => {
          const fwHandler = (fw) => {
            if (fw.options.name === widgetName) {
              subFormName = sfName
            }
          }

          const sfRef = this.subFormRefList[sfName]
          traverseFieldWidgetsOfContainer(sfRef.widget, fwHandler)
        })

        return subFormName
      },

      getSubFormNameByWidgetId(widgetId) {
        return getSubFormNameByFieldId(this.formJsonObj.widgetList, widgetId)
      },

      /**
       * 获取所有字段组件
       * @param staticWidgetsIncluded 是否包含按钮等静态组件，默认不包含
       * @returns {*[]}
       */
      getFieldWidgets(staticWidgetsIncluded = false) {
        return getAllFieldWidgets(this.formJsonObj.widgetList, staticWidgetsIncluded)
      },

       /**
       * 获取所有容器组件
       * @param skipDialogAndDrawer 是否跳过弹窗和抽屉内部组件，默认不跳过
       * @returns {*[]}
       */
       getContainerWidgets(skipDialogAndDrawer = false) {
        return getAllContainerWidgets(this.formJsonObj.widgetList, skipDialogAndDrawer)
      },

      /**
       * 增加外部组件引用，可通过getEC()方法获取外部组件，以便在VForm内部调用外部组件方法
       * @param componentName 外部组件名称
       * @param externalComponent 外部组件实例
       */
      addEC(componentName, externalComponent) {
        this.externalComponents[componentName] = externalComponent
      },

      /**
       * 判断外部组件是否可获取
       * @param componentName 外部组件名称
       * @returns {boolean}
       */
      hasEC(componentName) {
        return this.externalComponents.hasOwnProperty(componentName)
      },

      /**
       * 获取外部组件实例
       * @param componentName
       * @returns {*}
       */
      getEC(componentName) {
        return this.externalComponents[componentName]
      },

      /**
       * 设置或取消设置表单为只读查看模式
       * @param readonlyFlag
       */
      setReadMode(readonlyFlag = true) {
        this.readModeFlag = readonlyFlag
      },

      /**
       * 获取表单当前是否只读查看模式
       * @returns {boolean}
       */
      getReadMode() {
        return this.readModeFlag
      },

      /**
       * 获取globalDsv对象
       * @returns {*}
       */
      getGlobalDsv() {
        return this.globalDsv
      },

      /**
       * 执行数据源请求
       * @param dsName
       * @param localDsv
       */
      async executeDataSource(dsName, localDsv = {}) {
        let ds = getDSByName(this.formJsonObj.formConfig, dsName)
        let newDsv = new Object({})
        overwriteObj(newDsv, this.globalDsv)
        overwriteObj(newDsv, localDsv)
        return await runDataSourceRequest(ds, newDsv, this, false, this.$message)
      },

      /**
       * 获取父级VFormRender组件实例
       * @returns {object}
       */
      getParentFormRef() {
        return this.parentForm
      },

      /**
       * 当显示多级嵌套弹窗或抽屉时，获取最顶层VFormRender组件实例
       * @returns {object}
       */
      getTopFormRef() {
        if (!this.parentForm) {
          return this
        }

        let topFormRef = this.parentForm
        while (topFormRef.parentForm) {
          topFormRef = topFormRef.parentForm
        }

        return topFormRef
      },

      setChildFormRef(childFormRef) {
        this.childFormRef = childFormRef
      },

      getChildFormRef() {
        return this.childFormRef
      },

      /**
       * 是否弹窗、抽屉组件动态创建的v-form-render
       * @returns {boolean}
       */
      isDynamicCreation() {
        return this.dynamicCreation
      },

      setDialogOrDrawerRef(ddRef) {
        this.dialogOrDrawerRef = ddRef
      },

      /**
       * 获取子级VFormRender的包裹弹窗组件或抽屉组件实例ref
       * @returns {object}
       */
      getDialogOrDrawerRef() {
        return this.dialogOrDrawerRef
      },

      /**
       * 显示弹窗表单，动态创建v-form-render组件，option-data、global-dsv等属性继承父级表单
       * @param dialogName
       * @param formData
       * @param extraData
       * @param title
       */
      showDialog(dialogName, formData = {}, extraData = {}, title = '') {
        let topFormRef = this.getTopFormRef()
        let dialogCon = getContainerWidgetByName(topFormRef.widgetList, dialogName)
        if (!dialogName || (dialogCon.type !== 'vf-dialog')) {
          this.$message.error(this.i18nt('render.hint.refNotFound') + dialogName)
          return
        }
        let dFormJson = {
          widgetList: deepClone(dialogCon.widgetList),
          widgetViewList: deepClone(drawerCon.widgetViewList),
          formConfig: cloneFormConfigWithoutEventHandler(topFormRef.formConfig)
        }

        let wrapperDivId = generateId() + ''
        let dialogInstance = createVNode(DynamicDialog, {
          options: dialogCon.options,
          formJson: dFormJson,
          formData: formData || {},
          optionData: topFormRef.optionData,
          globalDsv: topFormRef.globalDsv,
          parentFormRef: this,
          extraData: extraData,
          wrapperId: wrapperDivId,
          title: title,
        }, this.$slots)
        dialogInstance.appContext = this.$root.$.appContext  //非常重要， 覆盖应用上下文！！

        let wrapperDiv = document.createElement("div")
        wrapperDiv.id = 'vf-dynamic-dialog-wrapper' + wrapperDivId
        document.body.appendChild(wrapperDiv)
        render(dialogInstance, wrapperDiv)
        document.body.appendChild( dialogInstance.el )
        return dialogInstance.component.ctx.show()
      },

      showDrawer(drawerName, formData = {}, extraData = {}, title = '') {
        let topFormRef = this.getTopFormRef()
        let drawerCon = getContainerWidgetByName(topFormRef.widgetList, drawerName)
        if (!drawerCon || (drawerCon.type !== 'vf-drawer')) {
          this.$message.error(this.i18nt('render.hint.refNotFound') + drawerName)
          return
        }
        let dFormJson = {
          widgetList: deepClone(drawerCon.widgetList),
          widgetViewList: deepClone(drawerCon.widgetViewList),
          formConfig: cloneFormConfigWithoutEventHandler(topFormRef.formConfig)
        }

        let wrapperDivId = generateId() + ''
        let drawerInstance = createVNode(DynamicDrawer, {
          options: drawerCon.options,
          formJson: dFormJson,
          formData: formData || {},
          optionData: topFormRef.optionData,
          globalDsv: topFormRef.globalDsv,
          parentFormRef: this,
          extraData: extraData,
          wrapperId: wrapperDivId,
          title: title,
        }, this.$slots)
        drawerInstance.appContext = this.$root.$.appContext  //非常重要， 覆盖应用上下文！！

        let wrapperDiv = document.createElement("div")
        wrapperDiv.id = 'vf-dynamic-drawer-wrapper' + wrapperDivId
        document.body.appendChild(wrapperDiv)
        render(drawerInstance, wrapperDiv)
        document.body.appendChild( drawerInstance.el )
        return drawerInstance.component.ctx.show()
      },

      /**
       * 判断表单是否处于设计器预览状态
       * @return {boolean}
       */
      isPreviewState() {
        return this.previewState
      },

      /**
       * 一次性设置formJson、formData和禁用表单
       * @param formJson
       * @param formData
       * @param disabledFlag
       */
      setFormJsonAndData(formJson, formData, disabledFlag = null) {
        this.setFormJson(formJson)
        this.$nextTick(() => {
          if (!!formData) {
            this.setFormData(formData)
            this.$nextTick(() => {
              if (!!disabledFlag) {
                this.disableForm()
              }
            })
          }
        })
      },

      /**
       * 清空表单所有组件（包含全局函数、自定义CSS代码）
       */
      setBlankFormJson() {
        let blankFormJson = {
          widgetList: [],
          formConfig: getDefaultFormConfig()
        }
        this.setFormJson(blankFormJson)
      },

      /**
       * 获取onChange事件是否由用户操作触发标志
       */
       getCETriggerFlag() {
        return this.changeEventTriggerFlag
      },

      /**
       * 设置表单内部组件创建时是否禁止触发onChange事件标志位
       * @param flag true禁止触发onChange事件，false不禁止
       */
      setCEOCDisabledFlag(flag) {
        this.changeEventOnCreatedDisabledFlag = flag
      },

      buildFormFieldSchema(formJson) {
        const fieldSchema = {}
        const formWidgetList = formJson ? formJson.widgetList : this.widgetList
        const allCws = getAllContainerWidgets(formWidgetList)
        let subFormCws = [], objectCws = []
        allCws.forEach(ctn => {
          if (widgetIsSubFormType(ctn)) {
            subFormCws.push(ctn.container)
          } else if (ctn.type === 'object-group') {
            objectCws.push(ctn.container)
          }
        })

        /* 处理子表单容器 */
        let allSFFields = []
        subFormCws.forEach(sf => {
          const sfFields = []
          traverseFieldWidgetsOfContainer(sf, (w) => {
            if (w.formItemFlag) {
              sfFields.push(w.options.name)
              allSFFields.push(w.options.name)
            }
          })
          fieldSchema[sf.options.name] = sfFields
        })

        /* 处理对象容器 */
        const allObjectFields = []
        objectCws.forEach(oc => {
          traverseFieldWidgetsOfContainer(oc, (w) => {
            //if (w.formItemFlag && (w.nameReadonly || w.virtualFlag)) {
            if (w.formItemFlag) {
              allObjectFields.push(w.options.name)
            }
          })
        })
        
        /* 处理主表单字段 */
        const mainFields = getAllFieldWidgets(formWidgetList, false, true, true)
        const mainFieldNames = []
        mainFields.forEach(fld => {
          mainFieldNames.push(fld.name)
        })
        fieldSchema['main'] = mainFieldNames

        return fieldSchema
      },

      //--------------------- 以上为组件支持外部调用的API方法 end ------------------//

    },
  }
</script>

<style lang="scss" scoped>
  .el-form :deep(.el-row) {
    padding: 8px;
    .el-col:not(.leftright-col){
      .el-scrollbar__view,
      .field-wrapper {
        height: 100%;
      }
    }
  }
</style>
<style lang="scss">
  .render-form.el-form--label-top .el-form-item__label {
    height: 26px !important;
    margin-top: 8px;
    margin-bottom: 2px !important;
  }

  .render-form .field-wrapper.form-textarea-label .el-form-item {
    align-items: flex-start;
  }
</style>
